
#include "TcpServer.hpp"
#include "Protocol.hpp"
#include "Calculator.hpp"
#include "Deamon.hpp"
#include <memory>

using namespace LogModule;
using cal_fun = std::function<Response(const Request &req)>;

// 不完整->继续读
// 完整-> 提取 -> 反序列化 -> Request -> 计算模块，进行处理
class Parse
{
public:
    Parse(cal_fun c) : _cal(c)
    {}
    std::string Entry(std::string &package)
    {
        // 1. 判断报文的完整性！
        std::string message;
        std::string respstr;
        std::cout << "package：" << package << std::endl;
        while (Decode(package, &message))
        {
            LOG(LogLevel::DEBUG) << "Content: \n" << message;
            if (message.empty())
                break;

            // 2. 反序列化， message是一个曾经被序列化的request
            Request req;
            if (!req.DeSerialize(message))
                break;

            std::cout << "#############" << std::endl;
            req.Print();
            std::cout << "#############" << std::endl;

            // 3. 计算
            Response resp = _cal(req);

            // 4. 序列化
            std::string res;
            resp.Serialize(res);
            LOG(LogLevel::DEBUG) << "序列化: \n" << res;
            
            // 5. 添加长度报头字段！
            Encode(res);

            LOG(LogLevel::DEBUG) << "Encode: \n" << res;

            // 6. 拼接应答
            respstr += res;
        }
        LOG(LogLevel::DEBUG) << "respstr: \n" << respstr;
        return respstr;
    }
private:
    cal_fun _cal;
};

int main(int argc,char* argv[])
{
    if (argc != 2)
    {
        std::cout << "Usage:./Server_tcp server_port" << std::endl;
        return 1;
    }
    //ENABLE_FILE_LOG();
    //Daemon(false, false);
    uint16_t port = std::stoi(argv[1]);
     // 1. 计算模块（应用层）为计算机用户提供服务
     Calculator mycal;
     // 2. 解析对象（表示层）数据处理（解码，加密解密，压缩解压缩）
     Parse myparse([&mycal](const Request &req){
         return mycal.Execute(req);
     });
     // 3. 通信模块（会话层）（管理应用程序之间的会话）
     // 只负责进行IO
     std::unique_ptr<TcpServer> tsvr = std::make_unique<TcpServer>([&myparse](std::string &package)->std::string{
         return myparse.Entry(package);
     },port);

    tsvr->InitServer();
    tsvr->Start();

    return 0;
}
